package com.bugreport.web;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.unitils.UnitilsJUnit4;
import org.unitils.spring.annotation.SpringApplicationContext;
import org.unitils.spring.annotation.SpringBeanByType;

import com.bugreport.test.utils.BugTrackerTestConnector1;
import com.bugreport.test.utils.BugTrackerTestConnector2;
import com.bugreport.utils.BugReportException;

@SpringApplicationContext("com/bugreport/web/ReportIssueControllerTestCase-spring.xml")
public class RICHandleRequestTestCase extends UnitilsJUnit4 {

	private static final Logger logger = Logger.getLogger(RICHandleRequestTestCase.class);

	@SpringBeanByType
	private ReportIssueController controller;

	@Test
	public void refuseGETRequest() {

		// Given
		MockHttpServletRequest request = new MockHttpServletRequest("GET", "/services/reportIssue.do");
		HttpServletResponse response = new MockHttpServletResponse();

		try {
			
			// When
			controller.handleRequest(request, response);
			fail("Expected exception");

		} catch (Exception ex) {

			// Then
			assertNotNull(ex);
			assertTrue(ex instanceof BugReportException);
			assertEquals(405, ((BugReportException) ex).getCode());

			logger.debug(ex.getMessage());
		}
	}

	@Test
	public void reportIssueFromWwwFooBar() throws Exception {

		// Given
		HttpServletRequest request = createHttpRequest("title", "description", "http://www.foo.bar", "content");
		HttpServletResponse response = new MockHttpServletResponse();

		// When
		ModelAndView mav = controller.handleRequest(request, response);

		// Then
		assertNotNull(mav);
		assertEquals(ReportIssueController.SUCCESS_VIEW, mav.getViewName());
		assertEquals(BugTrackerTestConnector1.ISSUE_ID,
				(String) mav.getModel().get(ReportIssueController.SUCCESS_ISSUE_ID));
	}

	@Test
	public void reportIssueFromWwwBarFoo() throws Exception {

		// Given
		HttpServletRequest request = createHttpRequest("title", "description", "www.bar.foo", "content");
		HttpServletResponse response = new MockHttpServletResponse();

		// When
		ModelAndView mav = controller.handleRequest(request, response);

		// Then
		assertNotNull(mav);
		assertEquals(ReportIssueController.SUCCESS_VIEW, mav.getViewName());
		assertEquals(BugTrackerTestConnector2.ISSUE_ID,
				(String) mav.getModel().get(ReportIssueController.SUCCESS_ISSUE_ID));
	}

	@Test
	public void reportIssueFromHttpsWwwFooBar() throws Exception {

		// Given
		HttpServletRequest request = createHttpRequest("title", "description", "https://www.foo.bar", "content");
		HttpServletResponse response = new MockHttpServletResponse();

		// When
		ModelAndView mav = controller.handleRequest(request, response);

		// Then
		assertNotNull(mav);
		assertEquals(ReportIssueController.SUCCESS_VIEW, mav.getViewName());
		assertEquals(BugTrackerTestConnector1.ISSUE_ID,
				(String) mav.getModel().get(ReportIssueController.SUCCESS_ISSUE_ID));
	}

	@Test
	public void failToReportIssueWithoutTitle() {

		// Given
		HttpServletRequest request = createHttpRequest(null, null, null, null);
		HttpServletResponse response = new MockHttpServletResponse();

		try {

			// When
			controller.handleRequest(request, response);
			fail("Expected exception");

		} catch (Exception ex) {

			// Then
			assertNotNull(ex);
			assertTrue(ex instanceof BugReportException);
			assertEquals(401, ((BugReportException) ex).getCode());

			logger.debug(ex.getMessage());
		}
	}

	@Test
	public void failToReportIssueWithEmptyTitle() {

		// Given
		HttpServletRequest request = createHttpRequest("   ", null, null, null);
		HttpServletResponse response = new MockHttpServletResponse();

		try {

			// When
			controller.handleRequest(request, response);
			fail("Expected exception");

		} catch (Exception ex) {

			// Then
			assertNotNull(ex);
			assertTrue(ex instanceof BugReportException);
			assertEquals(401, ((BugReportException) ex).getCode());

			logger.debug(ex.getMessage());
		}
	}

	@Test
	public void failToReportIssueWithoutDescription() {

		// Given
		HttpServletRequest request = createHttpRequest("title", null, null, null);
		HttpServletResponse response = new MockHttpServletResponse();

		try {

			// When
			controller.handleRequest(request, response);
			fail("Expected exception");

		} catch (Exception ex) {

			// Then
			assertNotNull(ex);
			assertTrue(ex instanceof BugReportException);
			assertEquals(402, ((BugReportException) ex).getCode());

			logger.debug(ex.getMessage());
		}
	}

	@Test
	public void failToReportIssueWithEmptyDescription() {

		// Given
		HttpServletRequest request = createHttpRequest("title", "   ", null, null);
		HttpServletResponse response = new MockHttpServletResponse();

		try {

			// When
			controller.handleRequest(request, response);
			fail("Expected exception");

		} catch (Exception ex) {

			// Then
			assertNotNull(ex);
			assertTrue(ex instanceof BugReportException);
			assertEquals(402, ((BugReportException) ex).getCode());

			logger.debug(ex.getMessage());
		}
	}

	@Test
	public void failToReportIssueWithoutPageUrl() {

		// Given
		HttpServletRequest request = createHttpRequest("title", "description", null, null);
		HttpServletResponse response = new MockHttpServletResponse();

		try {

			// When
			controller.handleRequest(request, response);
			fail("Expected exception");

		} catch (Exception ex) {

			// Then
			assertNotNull(ex);
			assertTrue(ex instanceof BugReportException);
			assertEquals(403, ((BugReportException) ex).getCode());

			logger.debug(ex.getMessage());
		}
	}

	@Test
	public void failToReportIssueWithEmptyPageUrl() {

		// Given
		HttpServletRequest request = createHttpRequest("title", "description", "   ", null);
		HttpServletResponse response = new MockHttpServletResponse();

		try {

			// When
			controller.handleRequest(request, response);
			fail("Expected exception");

		} catch (Exception ex) {

			// Then
			assertNotNull(ex);
			assertTrue(ex instanceof BugReportException);
			assertEquals(403, ((BugReportException) ex).getCode());

			logger.debug(ex.getMessage());
		}
	}

	@Test
	public void failToReportIssueWithoutPageHtmlContent() {

		// Given
		HttpServletRequest request = createHttpRequest("title", "description", "www.foo.bar", null);
		HttpServletResponse response = new MockHttpServletResponse();

		try {

			// When
			controller.handleRequest(request, response);
			fail("Expected exception");

		} catch (Exception ex) {

			// Then
			assertNotNull(ex);
			assertTrue(ex instanceof BugReportException);
			assertEquals(404, ((BugReportException) ex).getCode());

			logger.debug(ex.getMessage());
		}
	}

	@Test
	public void failToReportIssueWithEmptyPageHtmlContent() {

		// Given
		HttpServletRequest request = createHttpRequest("title", "description", "www.foo.bar", "    ");
		HttpServletResponse response = new MockHttpServletResponse();

		try {

			// When
			controller.handleRequest(request, response);
			fail("Expected exception");

		} catch (Exception ex) {

			// Then
			assertNotNull(ex);
			assertTrue(ex instanceof BugReportException);
			assertEquals(404, ((BugReportException) ex).getCode());

			logger.debug(ex.getMessage());
		}
	}

	private HttpServletRequest createHttpRequest(String title, String description, String pageUrl,
			String pageHtmlContent) {

		MockHttpServletRequest request = new MockHttpServletRequest("POST", "/services/reportIssue.do");

		request.addParameter(ReportIssueController.PARAM_ISSUE_TITLE, title);
		request.addParameter(ReportIssueController.PARAM_ISSUE_DESCRIPTION, description);
		request.addParameter(ReportIssueController.PARAM_ISSUE_PAGE_URL, pageUrl);
		request.addParameter(ReportIssueController.PARAM_ISSUE_PAGE_PAGE_HTML_CONTENT, pageHtmlContent);

		return request;
	}
}
